Micron Document
baubs git

Node / mirrors / respira / files / src / utils / penParser.ts

Displaying Raw • Download

src/utils/penParser.ts fix/pattern-rendering-and-coordinate-bugs (abf7b9a6) Text, 4.15 KB

import type { PenData, PenStitch, PenColorBlock } from '../types/machine';

// PEN format flags
const PEN_FEED_DATA = 0x01; // Y-coordinate low byte, bit 0
const PEN_COLOR_END = 0x03; // X-coordinate low byte, bits 0-2
const PEN_DATA_END = 0x05; // X-coordinate low byte, bits 0-2

export function parsePenData(data: Uint8Array): PenData {
if (data.length < 4 || data.length % 4 !== 0) {
throw new Error(\\`Invalid PEN data size: ${data.length} bytes\\`);
}

const stitches: PenStitch[] = [];
const colorBlocks: PenColorBlock[] = [];
const stitchCount = data.length / 4;

let currentColorStart = 0;
let currentColor = 0;
let minX = Infinity, maxX = -Infinity;
let minY = Infinity, maxY = -Infinity;

console.log(\\`Parsing PEN data: ${data.length} bytes, ${stitchCount} stitches\\`);

for (let i = 0; i < stitchCount; i++) {
const offset = i * 4;

// Extract coordinates (shifted left by 3 bits in PEN format)
const xRaw = data[offset] | (data[offset + 1] << 8);
const yRaw = data[offset + 2] | (data[offset + 3] << 8);

// Extract flags from low 3 bits
const xFlags = data[offset] & 0x07;
const yFlags = data[offset + 2] & 0x07;

// Decode coordinates (shift right by 3 to get actual position)
// The coordinates are stored as signed 16-bit values, left-shifted by 3
// Step 1: Clear the flag bits (low 3 bits) from the raw values
const xRawClean = xRaw & 0xFFF8;
const yRawClean = yRaw & 0xFFF8;

// Step 2: Convert from unsigned 16-bit to signed 16-bit
let xSigned = xRawClean;
let ySigned = yRawClean;
if (xSigned > 0x7FFF) xSigned = xSigned - 0x10000;
if (ySigned > 0x7FFF) ySigned = ySigned - 0x10000;

// Step 3: Shift right by 3 (arithmetic shift, preserves sign)
const x = xSigned >> 3;
const y = ySigned >> 3;

const stitch: PenStitch = {
x,
y,
flags: (xFlags & 0x07) | (yFlags & 0x07),
isJump: (yFlags & PEN_FEED_DATA) !== 0,
};

stitches.push(stitch);

// Track bounds
if (!stitch.isJump) {
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
minY = Math.min(minY, y);
maxY = Math.max(maxY, y);
}

// Check for color change or data end
if (xFlags === PEN_COLOR_END) {
const block: PenColorBlock = {
startStitch: currentColorStart,
endStitch: i,
colorIndex: currentColor,
};
colorBlocks.push(block);

console.log(
\\`Color ${currentColor}: stitches ${currentColorStart}-${i} (${
i - currentColorStart + 1
} stitches)\\`
);

currentColor++;
currentColorStart = i + 1;
} else if (xFlags === PEN_DATA_END) {
if (currentColorStart < i) {
const block: PenColorBlock = {
startStitch: currentColorStart,
endStitch: i,
colorIndex: currentColor,
};
colorBlocks.push(block);

console.log(
\\`Color ${currentColor} (final): stitches ${currentColorStart}-${i} (${
i - currentColorStart + 1
} stitches)\\`
);

currentColor++;
}
console.log(\\`Data end marker at stitch ${i}\\`);
break;
}
}

const result: PenData = {
stitches,
colorBlocks,
totalStitches: stitches.length,
colorCount: colorBlocks.length,
bounds: {
minX: minX === Infinity ? 0 : minX,
maxX: maxX === -Infinity ? 0 : maxX,
minY: minY === Infinity ? 0 : minY,
maxY: maxY === -Infinity ? 0 : maxY,
},
};

console.log(
\\`Parsed: ${result.totalStitches} stitches, ${result.colorCount} colors\\`
);
console.log(\\`Bounds: (${result.bounds.minX}, ${result.bounds.minY}) to (${result.bounds.maxX}, ${result.bounds.maxY})\\`);

return result;
}

export function getStitchColor(penData: PenData, stitchIndex: number): number {
for (const block of penData.colorBlocks) {
if (stitchIndex >= block.startStitch && stitchIndex <= block.endStitch) {
return block.colorIndex;
}
}
return -1;
}

Served by rngit 1.3.3 - Generated in 0.03s